package vip.youngboy.freejump.db.impl.mysql;

import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Component;
import vip.youngboy.freejump.db.DBHelper;
import vip.youngboy.freejump.db.TableOperator;
import vip.youngboy.freejump.db.constrants.ColumnType;
import vip.youngboy.freejump.db.constrants.DBType;
import vip.youngboy.freejump.db.model.DBColumn;
import vip.youngboy.freejump.db.model.DBTable;

import java.util.*;

@Component
public class MySqlDBHelper extends DBHelper {

    private static Logger logger = LoggerFactory.getLogger(MySqlDBHelper.class);

    public MySqlDBHelper(JdbcTemplate jdbcTemplate) {
        this.jdbcTemplate = jdbcTemplate;
    }

    @Override
    public DBType supportType() {
        return DBType.MYSQL;
    }

    @Override
    public TableOperator createTableOperator(DBTable<? extends DBColumn> DBTable, JdbcTemplate jdbcTemplate) {
        return new MySqlTableOperator(DBTable, jdbcTemplate);
    }

    @Override
    public Map<String, String> getTableNames(String tableName) {
        String sql = "select table_name,table_comment from information_schema.tables t where t.table_type='BASE TABLE' AND t.table_schema=DATABASE()";
        List list;
        if (StringUtils.isNotEmpty(tableName)) {
            sql = sql + " AND TABLE_NAME LIKE ?";
            list = this.jdbcTemplate.queryForList(sql, new Object[]{"%" + tableName + "%"});
        } else {
            list = this.jdbcTemplate.queryForList(sql);
        }

        Map<String, String> map = new LinkedHashMap();
        Iterator var5 = list.iterator();

        while (var5.hasNext()) {
            Map<String, Object> m = (Map) var5.next();
            map.put(m.get("table_name").toString(), m.get("table_comment").toString());
        }

        return map;
    }

    @Override
    public List<String> getViewNames(String viewName) {
        String sql = "show table status where comment='view'";
        if (StringUtils.isNotEmpty(viewName)) {
            sql = sql + " AND NAME LIKE ?";
        }

        List<String> list = new ArrayList();
        List<Map<String, Object>> results = this.jdbcTemplate.queryForList(sql, new Object[]{"%" + viewName + "%"});
        Iterator var5 = results.iterator();

        while (var5.hasNext()) {
            Map<String, Object> line = (Map) var5.next();
            list.add(line.get("Name").toString());
        }

        return list;
    }

    @Override
    public DBTable<DBColumn> getTable(String tableName) {
        DBTable<DBColumn> DBTable = new DBTable();
        Map<String, String> tableNames = this.getTableNames(tableName);
        if (tableNames.isEmpty()) {
            throw new RuntimeException(String.format("根据表名[%s]获取不到表", tableName));
        } else {
            DBTable.setName(tableName);
            DBTable.setComment((String) tableNames.get(tableName));
            DBTable.setColumns(this.getColumns(tableName));
            return DBTable;
        }
    }

    @Override
    public DBTable<DBColumn> getView(String viewName) {
        DBTable<DBColumn> DBTable = new DBTable();
        List<String> viewNames = this.getViewNames(viewName);
        if (viewNames.isEmpty()) {
            throw new RuntimeException(String.format("根据视图名[%s]获取不到视图", viewName));
        } else {
            DBTable.setName(viewName);
            DBTable.setComment(viewName);
            DBTable.setColumns(this.getColumns(viewName));
            return DBTable;
        }
    }

    @Override
    public boolean supportPartition(String tableName) {
        String sql = "select count(*) from information_schema.partitions where table_name=?;";
        Integer rtn = (Integer) this.jdbcTemplate.queryForObject(sql, Integer.class, new Object[]{tableName});
        return rtn > 0;
    }

    @Override
    public boolean isExsitPartition(String tableName, String partName) {
        String sql = "select count(*) from information_schema.partitions where table_name=? and partition_name =?;";
        String[] args = new String[]{tableName, "P_" + partName.toUpperCase()};
        Integer rtn = (Integer) this.jdbcTemplate.queryForObject(sql, args, Integer.class);
        return rtn > 0;
    }

    @Override
    public void createPartition(String tableName, String partName) {
        String sql = "alter table " + tableName + " add partition (partition P_" + partName.toUpperCase() + " values in ('" + partName + "')) ";
        this.jdbcTemplate.execute(sql);
    }

    private List<DBColumn> getColumns(String name) {
        String sql = "SELECT * FROM  INFORMATION_SCHEMA.COLUMNS  WHERE TABLE_SCHEMA=DATABASE() AND TABLE_NAME=?";
        List<Map<String, Object>> list = this.jdbcTemplate.queryForList(sql, new Object[]{name});
        List<DBColumn> DBColumns = new ArrayList();

        DBColumn DBColumn;
        for (Iterator var5 = list.iterator(); var5.hasNext(); DBColumns.add(DBColumn)) {
            Map<String, Object> map = (Map) var5.next();
            DBColumn = new DBColumn();
            DBColumn.setComment(this.getOrDefault(map, "COLUMN_COMMENT", "").toString());
            DBColumn.setDefaultValue(map.get("COLUMN_DEFAULT") == null ? null : map.get("COLUMN_DEFAULT").toString());
            DBColumn.setName(this.getOrDefault(map, "COLUMN_NAME", "").toString());
            DBColumn.setPrimary("PRI".equals(this.getOrDefault(map, "COLUMN_KEY", "")));
            DBColumn.setRequired("NO".equals(this.getOrDefault(map, "IS_NULLABLE", "")));
            DBColumn.setType(ColumnType.getByDbDataType(map.get("DATA_TYPE").toString()).getKey());
            if (ColumnType.VARCHAR.equalsWithKey(DBColumn.getType())) {
                DBColumn.setLength(Integer.parseInt(this.getOrDefault(map, "CHARACTER_MAXIMUM_LENGTH", "0").toString()));
            }

            if (ColumnType.NUMBER.equalsWithKey(DBColumn.getType())) {
                DBColumn.setLength(Integer.parseInt(this.getOrDefault(map, "NUMERIC_PRECISION", "0").toString()));
                DBColumn.setDecimal(Integer.parseInt(this.getOrDefault(map, "NUMERIC_SCALE", "0").toString()));
            }
        }

        return DBColumns;
    }

}
